/*
	Copyright (C) 2010 2011 Rémi Thebault

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TASKVIEWHELPER_H
#define TASKVIEWHELPER_H

#include <QVariant>

#include <procycle/task.h>
#include <procycle/macrotask.h>
#include <procycle/cycle.h>


class TaskViewHelper {
public:
	TaskViewHelper(PC::Task* task) :
		m_task(task)
	{}

	// true unless property set to false
	bool isExpanded() {
		if (m_task) {
			QVariant v = m_task->property("expanded");
			if (v.isValid() && !v.toBool()) {
				return false;
			}
		}
		return true;
	}


	void setExpanded (bool expanded, bool recursive=false) {
		if (PC::MacroTask* mt = dynamic_cast<PC::MacroTask*>(m_task)) {
			if (mt->parent()) {			// root never collapses
				mt->setProperty("expanded", QVariant(expanded));
			}
			if (recursive) {
				for (PC::Task::const_iterator ti=mt->taskBegin(); ti!=mt->taskEnd(); ++ti) {
					TaskViewHelper tvh (*ti);
					tvh.setExpanded(expanded, recursive);
				}
			}
		}
	}



	int visualHeight() {
		if (PC::MacroTask* mt = dynamic_cast<PC::MacroTask*>(m_task)) {
			int num = 1;
			if (isExpanded()) {
				for (PC::Task::const_iterator ti=mt->taskBegin(); ti!=mt->taskEnd(); ++ti) {
					TaskViewHelper tvh (*ti);
					num += tvh.visualHeight();
				}
			}
			return num;
		}
		return 1;
	}

	int visualChildrenHeight() {
		return visualHeight() - 1;
	}

	int visualChildPos(PC::Task* child) {
		PC::MacroTask* mt = dynamic_cast<PC::MacroTask*>(m_task);
		if (mt == child->parent()) {
			int pos = 0;
			for (PC::Task::const_iterator ti=mt->taskBegin(); ti!=mt->taskEnd(); ++ti) {
				if (child == *ti) {
					return pos;
				}
				TaskViewHelper tvh (*ti);
				pos += tvh.visualHeight();
			}
			return pos;
		}
		return -1;
	}

	int visualSubChildPos(PC::Task* child) {
		if (PC::MacroTask* mt = dynamic_cast<PC::MacroTask*>(m_task)) {
			int pos = 0;
			for (PC::Task::const_iterator ti=mt->taskBegin(); ti!=mt->taskEnd(); ++ti) {
				if (child == *ti) {
					return pos;
				}
				TaskViewHelper tvh (*ti);
				int scp = tvh.visualSubChildPos(child);
				if (scp != -1) {
					return 1 + pos + scp;
				}
				pos += tvh.visualHeight();
			}
		}
		return -1;
	}


	QList<int> visualChildrenPos() {
		QList<int> childrenPos;
		PC::MacroTask* mt = dynamic_cast<PC::MacroTask*>(m_task);
		if (mt && isExpanded() && mt->taskCount() > 0) {
			int pos = 0;
			int height = 0;
			for (int i=0; i<mt->taskCount(); i++) {
				TaskViewHelper tvh (mt->task(i));
				pos += height;
				height = tvh.visualHeight();
				childrenPos.append(pos);
			}
		}
		return childrenPos;
	}

	int visualPos() {
		if (m_task) {
			PC::MacroTask* parent = m_task->parent();
			if(parent) {
				TaskViewHelper ptvh (parent);
				return ptvh.visualChildPos(m_task);
			}
		}
		return -1;
	}


	int relativeVisualTaskPos(int currentPos, QString r_tbsId) {
		if (PC::MacroTask* mt = dynamic_cast<PC::MacroTask*>(m_task)) {
			bool ok;
			int point = r_tbsId.indexOf('.');
			if (point == -1) {
				int pos = r_tbsId.toInt(&ok);
				if (!ok || pos < 0 || pos >= mt->taskCount()) {
					return -1;
				}
				return currentPos + visualChildPos(mt->task(pos));
			}
			QString befPoint = r_tbsId.left(point);
			QString aftPoint = r_tbsId.right(r_tbsId.length() - (point+1));
			int pos = befPoint.toInt(&ok);
			if (!ok || pos < 0 || pos >= mt->taskCount()) {
				return -1;
			}
			PC::Task* child = mt->task(pos);
			currentPos += visualChildPos(child);
			TaskViewHelper ctvh (child);
			return ctvh.relativeVisualTaskPos(currentPos, aftPoint);
		}
		return -1;
	}


	int absoluteVisualPos() {
		if (m_task) {
			PC::Cycle* cycle = m_task->cycle();
			if (cycle) {
				TaskViewHelper ctvh (cycle);
				return ctvh.relativeVisualTaskPos(0, m_task->tbsId());
			}
		}
		return -1;
	}

private:
	PC::Task* m_task;
};



#endif // TASKVIEWHELPER_H
